<?php
/** TOKEN 的创建，校验与销毁 */

namespace app\common;

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use \Exception;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\ValidationData;
use think\facade\Cache;

class JwtToken
{
    const REDIS_USER_PREFIX = 'app:login:uid_';

    /**
     * 创建生成 TOKEN
     * User: zhouyao
     * Date: 2018/9/15
     * Time: 下午7:01
     * @param null $uid
     * @return bool|string
     */
    public static function createToken($uid = null)
    {
        if (is_null($uid))
            return false;

        $signer = new Sha256();
        $token = (new Builder())->setIssuer(config('app.app_host'))
            ->setAudience(config('app.app_host'))
            ->setId(config('app.jwt_token_user'), true)
            ->setIssuedAt(time())
            ->setExpiration(time() + (3600 * 8))
            ->set('uid', $uid)
            ->sign($signer, config('app.app_host'))
            ->getToken();

        //把token放入到Redis内 并保存有效期8小时
        Cache::store('redis')->set(self::REDIS_USER_PREFIX . $uid, (String) $token, 3600 * 8);

        return (String) $token;
    }

    /**
     * 清除 TOKEN
     * User: zhouyao
     * Date: 2018/9/15
     * Time: 下午7:03
     * @param null $token
     * @return bool
     */
    public static function destroyToken($token = null)
    {
        if (is_null($token) || empty($token)) {
            return false;
        }

        if (self::tokenCheck($token) === false) {
            return false;
        }

        $obj_token = (new Parser())->parse($token);
        $uid = $obj_token->getClaim('uid');

        //返回hash里面field是否存在
        Cache::store('redis')->rm(self::REDIS_USER_PREFIX . $uid);
        return true;
    }

    public static function validationToken($token = null)
    {
        if (empty($token) || is_null($token)) {
            return false;
        }

        if (self::tokenCheck($token) === false) {
            return false;
        }

        $uid = self::getTokenUid($token); //取出token里面保存的用户id

        $redis_user_token = Cache::store('redis')->get(self::REDIS_USER_PREFIX . $uid);
        //判断token与服务端token是否一致
        if ($redis_user_token != $token) {
            return false;
        }
        return true;
    }

    /**
     * 检测 TOKEN 是否有效
     * User: zhouyao
     * Date: 2018/9/15
     * Time: 下午7:04
     * @param $token
     * @return mixed
     */
    public static function tokenCheck($token)
    {
        if (is_null($token) || empty($token)) {
            return false;
        }

        $token = self::stringToObject($token);
        if ($token === false) {
            return false;
        }

        $signer = new Sha256();
        if (!$token->verify($signer, config('app.app_host'))) {//签名不正确
            return false;
        }
        $validationData = new ValidationData();
        $validationData->setIssuer(config('app.app_host'));
        $validationData->setAudience(config('app.app_host'));
        $validationData->setId(config('app.jwt_token_user'));

        return $token->validate($validationData);
    }

    /**
     * 把接收的字符串 token 转为对象
     * User: zhouyao
     * Date: 2018/9/15
     * Time: 下午7:13
     * @param null $token
     * @return bool|\Lcobucci\JWT\Token
     */
    public static function stringToObject($token = null)
    {
        try {
            return (new Parser())->parse($token);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 获取 token 里面保存的用户 id
     * User: zhouyao
     * Date: 2018/9/15
     * Time: 下午7:14
     * @param null $token
     * @return mixed|null
     */
    public static function getTokenUid($token = null)
    {
        $token = self::stringToObject($token);

        if ( false === $token) {
            return null;
        }

        return $token->getClaim('uid');
    }


}